package com.jason.lucene.example.search;

import com.jason.lucene.example.annotation.Unclear;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TermRangeQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.WildcardQuery;
import org.junit.Assert;
import org.junit.Test;

/**
 * 解析查询表达式测试 , 查询表达式中需要转移的字符 ：
 * \ + - ! ( ) : ^ ] { } ~  * ?
 *
 * @author he peng
 * @create 2017/12/6 19:38
 * @see
 */
public class QueryParserTest extends BaseSearchingTest {

    /**
     * 范围查询表达式测试
     * @throws Exception
     */
    @Unclear
    @Test
    public void testTermRangeQuery() throws Exception {

        QueryParser queryParser = new QueryParser("subject", new StandardAnalyzer());
        Query query = queryParser.parse("[A TO Z]");
        System.err.println("query =====> " + query);

        Assert.assertTrue(query instanceof TermRangeQuery);

        IndexSearcher searcher = new IndexSearcher(DirectoryReader.open(super.indexDir));
        TopDocs topDocs = searcher.search(query, 1000);
        for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
            System.err.println("hit doc =====> " + searcher.doc(scoreDoc.doc));
        }
    }

    @Test
    public void testWildcardQuery() throws Exception {
        QueryParser queryParser = new QueryParser("subject", new StandardAnalyzer());
        // 默认情况不支持项的开端包含通配符
        // Cannot parse '*java': '*' or '?' not allowed as first character in WildcardQuery
        // 若要改变这个默认限制需要调用 setAllowLeadingWildcard 方法 ， 但是会牺牲掉一部分性能
        queryParser.setAllowLeadingWildcard(true);
        Query query = queryParser.parse("*java");
        System.err.println("query =====> " + query);

        Assert.assertTrue(query instanceof WildcardQuery);

        IndexSearcher searcher = new IndexSearcher(DirectoryReader.open(super.indexDir));
        TopDocs topDocs = searcher.search(query, 1000);
        for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
            System.err.println("hit doc =====> " + searcher.doc(scoreDoc.doc));
        }

    }

    @Test
    public void testPhraseQuery() throws Exception {
        StandardAnalyzer standardAnalyzer = new StandardAnalyzer();
        QueryParser parser = new QueryParser("field", standardAnalyzer);
        Query query = parser.parse("\"This is Some Phrase*\"");
        System.err.println("query parse ==> " + query.toString("field"));
        Assert.assertEquals("aanalyzed" , "\"? ? some phrase\"" , query.toString("field"));

        // 单项短语会被优化成 TermQuery
        QueryParser parser1 = new QueryParser("filed", standardAnalyzer);
        Query query1 = parser1.parse("\"term\"");
        System.err.println("query1 parse ==> " + query1.toString("field"));
        Assert.assertTrue("reduced to TermQuery" , query1 instanceof TermQuery);
    }

    @Test
    public void testSlop() throws Exception {
        StandardAnalyzer standardAnalyzer = new StandardAnalyzer();
        QueryParser parser = new QueryParser("field", standardAnalyzer);
        Query query = parser.parse("\"exact phrase\"");
        System.err.println("query parse ==> " + query.toString("field"));
        Assert.assertEquals("zero slop" , "\"exact phrase\"" , query.toString("field"));

        QueryParser parser1 = new QueryParser("field", standardAnalyzer);
        parser1.setPhraseSlop(5);
        Query query1 = parser1.parse("\"sloppy phrase\"");
        System.err.println("query1 parse ==> " + query1.toString("field"));
        Assert.assertEquals("sloppy implicitly" , "\"sloppy phrase\"~5" , query1.toString("field"));

    }

    @Test
    public void testFuzzyQuery() throws Exception {
        QueryParser parser = new QueryParser("subject", new StandardAnalyzer());
        Query query = parser.parse("kountry\\~3");
        System.err.println("fuzzy query parser ==> " + query.toString());

        query = parser.parse("kountry\\~0.8");
        System.err.println("fuzzy query parser ==> " + query.toString());
    }

    @Test
    public void testAllDocsQuery() throws Exception {
        QueryParser parser = new QueryParser("subject", new StandardAnalyzer());
        Query query = parser.parse("*:*");
        System.err.println("fuzzy query parser ==> " + query.toString());
        Assert.assertTrue("match all docs query" , query instanceof MatchAllDocsQuery);
    }

    @Test
    public void testGrouping() throws Exception {
        QueryParser queryParser = new QueryParser("subject" , new StandardAnalyzer());
        Query query = queryParser.parse("(agile OR extreme) AND methodology");
        System.err.println("query1 parse ==> " + query.toString());
        Assert.assertTrue("boolean query" , query instanceof BooleanQuery);

        IndexSearcher searcher = new IndexSearcher(DirectoryReader.open(super.indexDir));
        TopDocs topDocs = searcher.search(query, 1000);
        for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
            System.err.println("hit doc =====> " + searcher.doc(scoreDoc.doc));
        }
    }
}
